﻿using System;
using System.Collections.Generic;
using System.Xml;
using BasecampRestAPI;
using NUnit.Framework;
using TestBasecampRestAPI.TestMoveToDoList;

namespace TestBasecampRestAPI
{
	[TestFixture]
	public class TestBasecamp
	{
		IBaseCamp _camp;
		FakeRestWebService _service;

		[SetUp]
		public void SetUp()
		{
			_service = FakeRestWebService.GetInstance();
			_camp = BaseCamp.GetInstance(_service);
		}

		[Test]
		public void Construct()
		{
			Assert.IsNotNull(_camp);
		}

		public const int Person1Id = 3514656;
		public const int Person2Id = 3514657;

		[Test]
		public void GetCurrentPerson()
		{
			SetupResponseXml(Properties.Resources.FakePerson);
			IPerson person = _camp.CurrentPerson;
			AssertGetWebRequestResponseForPath("me.xml");
			Assert.IsNotNull(person);
			Assert.AreEqual(Person1Id, person.Id);
			Assert.AreEqual("Gumby", person.FirstName);
		}

		[Test]
		public void GetPeople()
		{
			SetupResponseXml(Properties.Resources.FakePeople);
			IPerson[] people = _camp.People;
			AssertGetWebRequestResponseForPath("people.xml");
			Assert.IsNotNull(people);
			Assert.AreEqual(2, people.Length);
			Assert.AreEqual(Person1Id, people[0].Id);
			Assert.AreEqual(Person2Id, people[1].Id);
		}

		[Test]
		public void GetCompanies()
		{
			SetupResponseXml(Properties.Resources.FakeCompanies);
			ICompany[] companies = _camp.Companies;
			AssertGetWebRequestResponseForPath("companies.xml");
			Assert.IsNotNull(companies);
			Assert.AreEqual(2, companies.Length);
			Assert.AreEqual(1776, companies[0].Id);
			Assert.AreEqual(1777, companies[1].Id);
		}

		[Test]
		public void GetCompanyById()
		{
			SetupResponseXml(Properties.Resources.FakeCompany);
			ICompany company = _camp.GetCompanyById(1776);
			AssertGetWebRequestResponseForPath(Company.PathForId(1776));
			Assert.IsNotNull(company);
			Assert.AreEqual(1776, company.Id);
		}

		[Test]
		public void GetCategoryById()
		{
			SetupResponseXml(Properties.Resources.FakeCategory);
			ICategory category = _camp.GetCategoryById(1366);
			AssertGetWebRequestResponseForPath(Category.PathForId(1366));
			Assert.IsNotNull(category);
			Assert.AreEqual(1366, category.Id);
		}

		[Test]
		public void GetPersonById()
		{
			SetupResponseXml(Properties.Resources.FakePerson);
			IPerson person = _camp.GetPersonById(Person1Id);
			AssertGetWebRequestResponseForPath(Person.PathForId(Person1Id));
			Assert.IsNotNull(person);
			Assert.AreEqual(Person1Id, person.Id);
			Assert.AreEqual("Gumby", person.FirstName);
		}

		[Test]
		public void GetMessageById()
		{
			SetupResponseXml(Properties.Resources.FakePost);
			IPost message = _camp.GetMessageById(4404);
			AssertGetWebRequestResponseForPath(Post.PathForId(4404));
			Assert.IsNotNull(message);
			Assert.AreEqual(4404, message.Id);
		}

		[Test]
		public void GetProjectsEmptyList()
		{
			SetupResponseXml("<projects></projects>");
			IList<IProject> projects = _camp.Projects;
			AssertGetWebRequestResponseForPath("projects.xml");
			Assert.IsNotNull(projects);
			Assert.AreEqual(0, projects.Count);
		}

		[Test]
		public void GetProjectsTwoProjects()
		{
			SetupResponseXml(string.Format("<projects>{0}{1}</projects>",
				Properties.Resources.FakeProject, Properties.Resources.FakeProject2));
			IProject[] projects = _camp.Projects;
			AssertGetWebRequestResponseForPath("projects.xml");
			Assert.IsNotNull(projects);
			Assert.AreEqual(2, projects.Length);
			Assert.AreEqual(6969, projects[0].Id);
			Assert.AreEqual(1942, projects[1].Id);
		}

		[Test]
		public void GetProjectById()
		{
			SetupResponseXml(Properties.Resources.FakeProject);
			const int id = 6969;
			IProject project = _camp.GetProjectById(id);

			AssertGetWebRequestResponseForPath(Project.PathForId(id));

			Assert.IsNotNull(project);
			Assert.AreEqual(id, project.Id);
		}

		[Test]
		public void GetProject2ById()
		{
			SetupResponseXml(Properties.Resources.FakeProject2);
			const int id = 1942;
			IProject project = _camp.GetProjectById(id);

			AssertGetWebRequestResponseForPath(Project.PathForId(id));

			Assert.IsNotNull(project);
			Assert.AreEqual(id, project.Id);
		}

		[Test]
		public void DeleteCategory()
		{
			const int id = 1366;
			_camp.DeleteCategoryById(id);
			Assert.IsTrue(_service.DeleteRequestCalled);
			Assert.AreEqual(Category.PathForId(id), _service.DeleteRequestLastRequestPath);
		}

		[Test]
		public void DeleteMessage()
		{
			const int id = 4404;
			_camp.DeleteMessageById(id);
			Assert.IsTrue(_service.DeleteRequestCalled);
			Assert.AreEqual(Post.PathForId(id), _service.DeleteRequestLastRequestPath);
		}

		private void AssertGetWebRequestResponseForPath(string path)
		{
			Assert.IsTrue(_service.GetRequestResponseElementCalled);
			Assert.AreEqual(path, _service.GetRequestResponseElementLastRequestPath);
			AssertGetWebRequestResponse();
		}

		private void SetupResponseXml(string xml)
		{
			_service.GetRequestResponseElementFakeResult = GetElementForXml(xml);
		}

		private void AssertGetWebRequestResponse()
		{
			Assert.AreEqual(HttpVerb.Get, _service.GetRequestResponseElementLastVerb);
		}

		public static XmlElement GetElementForXml(string xml)
		{
			return GetXmlDocument(xml).DocumentElement;
		}

		public static XmlDocument GetXmlDocument(string xml)
		{
			XmlDocument document = new XmlDocument();
			document.LoadXml(xml);
			return document;
		}
	}
}
